#!/anaconda3/envs/FEALPy/bin python3.8
# -*- coding: utf-8 -*-
# ---
# @Software: PyCharm
# @File: conftest.py
# @Author: ---
# @Institution: --- University, ---, China
# @E-mail: ---@---.com, ---@---.edu.cn
# @Site: 
# @Time: 6月 25, 2024
# ---
import pytest
import json
from py.xml import html
import pandas as pd
from tqdm import tqdm

# 定义全局变量
TEST_CASES_PATH = 'data/youbangtongbu.xlsx'

class TestResultCollector:
    def __init__(self, results, total_tests, progress_bar):
        self.results = results
        self.total_tests = total_tests
        self.progress_bar = progress_bar
        self.completed_tests = 0

    @pytest.hookimpl(hookwrapper=True)
    def pytest_runtest_makereport(self, item, call):
        outcome = yield  # 产出测试结果

        # 获取测试结果
        report = outcome.get_result()

        # 只在call阶段记录结果
        if report.when == "call":
            if "test_case" in item.fixturenames:
                # 获取测试用例的描述
                test_case = item.funcargs["test_case"]
                description = test_case.get('description', '')

                # 判断测试结果
                result = 'pass' if report.passed else 'fail'
                reason = "无异常"

                # 如果测试失败
                if report.failed:
                    # 获取长错误信息
                    longrepr = str(report.longrepr)

                    # 判断是否为断言错误
                    if "AssertionError" in longrepr:
                        # 提取 AssertionError 后面的具体错误信息
                        reason_lines = longrepr.splitlines()
                        for line in reason_lines:
                            if line.strip().startswith("E               AssertionError:"):
                                reason = line.strip().replace("E               AssertionError:", "")
                                break
                    else:
                        # 捕获其他未分类的错误原因
                        reason = longrepr

                # 将测试结果添加到结果列表中
                self.results.append({'description': description, 'result': result, 'reason': reason})

                # 已完成的测试数加一
                self.completed_tests += 1

                # 更新进度条
                self.progress_bar.update(1)


    def save_results(self):
        with open(self.result_file, 'w') as f:
            json.dump(self.results, f)


def pytest_configure(config):
    """
    注册插件
    """
    df = pd.read_excel(TEST_CASES_PATH)
    total_tests = len(df)
    progress_bar = tqdm(total=total_tests, desc="测试进度")
    collector = TestResultCollector([], total_tests, progress_bar)
    config.pluginmanager.register(collector, "test_results_collector")


# 定义一个会话级别的fixture，用于加载测试数据
def pytest_generate_tests(metafunc):
    if 'test_case' in metafunc.fixturenames:
        test_cases = []
        try:
            df = pd.read_excel(TEST_CASES_PATH)
            test_data = df.to_dict(orient='records')
            for row in test_data:
                test_cases.append(row)
        except Exception as e:
            print(f"Error reading test cases from {TEST_CASES_PATH}: {e}")
            test_cases.append({'description': 'Error reading test cases', 'result': 'fail', 'reason': str(e)})

        metafunc.parametrize("test_case", test_cases)

@pytest.hookimpl(tryfirst=True)
def pytest_html_report_title(report):
    """
    设置 HTML 报告的标题。
    """
    report.title = "微保险种遍历报告"


@pytest.hookimpl(optionalhook=True)
def pytest_html_results_table_header(cells):
    """
    在 HTML 报告的表头中插入描述列。
    """
    cells.insert(1, html.th('Description'))


@pytest.hookimpl(optionalhook=True)
def pytest_html_results_table_row(report, cells):
    """
    在 HTML 报告的每一行中插入描述列的数据。
    """
    cells.insert(1, html.td(getattr(report, 'description', '')))


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
    """
    在生成测试报告时，添加描述字段的信息。
    """
    outcome = yield
    report = outcome.get_result()
    if "test_case" in item.fixturenames:
        test_case = item.funcargs["test_case"]
        report.description = test_case.get('description', '')


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
    """
    在每个测试用例执行时动态设置__doc__属性。
    """
    if "test_case" in item.fixturenames:
        test_case = item.funcargs["test_case"]
        item.function.__doc__ = test_case.get('description', '')
    yield
